#pragma once



#include "qgraphics.h"
#include "qdebug.h"

namespace micro
{
namespace gui
{




class QWindow
{
protected:
    HWND			_window;
    //explicit QWindow(QWindow*)	{	}
    QWindow( const QWindow & );            // no implementation
    void operator=( const QWindow & );     // no implementation

public:
    QWindow( HWND newWindow = nullptr )
    {
        _window =  newWindow;
    }
    virtual ~QWindow()
    {
        Destroy();
    }

    virtual bool	Create( QWindow * pParent = nullptr, int id = 0, UINT style = 0 );
    virtual LPCTSTR GetWndClassName()
    {
        return _T( "QWIN" );
    }


    bool CreateBaseWindowEx( DWORD exStyle, LPCTSTR className,
                             LPCTSTR windowName, DWORD style,
                             QRect & rect,
                             QWindow * parentWindow, UINT_PTR idOrHMenu = 0,
                             HINSTANCE instance = 0, LPVOID createParam = 0 );

    bool CreateBaseWindow( LPCTSTR className,
                           LPCTSTR windowName, DWORD style,
                           QRect & rect,
                           QWindow * parentWindow, int idOrHMenu = 0,
                           HINSTANCE instance = 0, LPVOID createParam = 0 );


    LRESULT SendMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 )
    {
        return ::SendMessage( _window, message, wParam, lParam ) ;
    }

    bool SetWindowText( LPCTSTR lpString )
    {
        return 0 != ::SetWindowText( _window, lpString );
    }
    bool PostMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 )
    {
        return toBool( ::PostMessage( _window, message, wParam, lParam ) ) ;
    }


    void CenterWindow( QWindow * pWndToCenterOn = nullptr );
    void CenterWindow2( HWND hWndCenter = nullptr );




    //unicode sublass
    bool SubclassWindow();
    bool UnSubclassWindow();
    static int  PrintMessage( LPCTSTR msg, LPCTSTR cap = _T( "Message" ), UINT flags = MB_OK )
    {
        return ::MessageBox( ::GetActiveWindow(), msg, cap, flags );
    }
protected:

    bool	RegisterClass( WNDCLASS & wc );

    //poarta de intrare a mesajelor
    static	LRESULT CALLBACK StaticWindowProcInit( HWND, UINT, WPARAM, LPARAM );		//poarta initiala
    static	LRESULT CALLBACK StaticWindowProc( HWND, UINT, WPARAM, LPARAM );			//poarta dupa primul apel


    //unicode subclassing
    static	LRESULT CALLBACK SubclassWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,  UINT_PTR uIdSubclass, DWORD_PTR dwRefData );
    LRESULT  DefWindowProc( UINT uID, WPARAM wParam, LPARAM lParam );


protected:
    virtual bool OnPreRegisterClass( WNDCLASS & );
    virtual bool OnPreCreate( CREATESTRUCT & cs );
    virtual void PreSubclassWindow() { }
    virtual bool PreTranslateMessage( MSG * pMsg ); //called from QApp


    virtual bool OnMessage( UINT message, WPARAM wParam, LPARAM lParam, LRESULT & lResult );
    virtual bool OnCommand( WPARAM wParam, LPARAM lParam );
    virtual bool OnSysCommand( UINT id, LPARAM lParam );
    virtual bool OnUserMessage( UINT msg, WPARAM wparam, LPARAM lParam );

    virtual bool OnNotify( UINT_PTR controlID, LPNMHDR lParam, LRESULT & lResult )
    {
        return false;
    }
    virtual bool OnParentNotify( UINT, LPARAM )
    {
        return false;
    }


    virtual LRESULT OnReflectedNotify( LPNMHDR pNMHDR, BOOL & bNotifyParent )
    {
        return 0;
    }


    virtual	bool OnNotifyFrame( WPARAM /*wParam*/, LPARAM /*lParam*/ )
    {
        return false;
    }
    virtual bool OnNotifyReflect( WPARAM /*wParam*/, LPARAM /*lParam*/ )
    {
        return  false;
    }

    virtual bool OnTimer( UINT_PTR id );
    virtual bool OnSize( int type, int cx, int cy );
    virtual bool OnGetMinMaxInfo( LPMINMAXINFO );
    virtual bool OnMove( int xpos, int ypos );
    virtual bool OnClose( void );
    virtual bool OnMoving( QRect * pRect );
    virtual bool OnPosChanging( WINDOWPOS * );
    virtual bool OnPosChanged( WINDOWPOS * );


    virtual bool OnCreateClient( void );
    virtual bool OnNcCreate( void );
    virtual bool OnDestroy( void );
    virtual bool OnNcDestroy( void );

    virtual bool OnEraseBackground( QGraphics * );
    virtual bool OnPaint( QGraphics * );


    virtual bool OnLButtonDown( UINT flags, QPoint & point );
    virtual bool OnLButtonUp( UINT flags, QPoint & point );
    virtual bool OnLButtonDblClk( UINT flags, QPoint & point );
    virtual bool OnRButtonDown( UINT flags, QPoint & point );
    virtual bool OnRButtonUp( UINT flags, QPoint & point );
    virtual bool OnRButtonDblClk( UINT flags, QPoint & point );
    virtual bool OnMButtonDown( UINT flags, QPoint & point );
    virtual bool OnMButtonUp( UINT flags, QPoint & point );
    virtual bool OnMButtonDblClk( UINT flags, QPoint & point );
    virtual bool OnDropFiles( HDROP );


    virtual bool OnMouseWheel( UINT flags, int delta,  QPoint & p );
    virtual bool OnMouseHWheel( UINT flags, int delta,  QPoint & p );

    virtual bool OnContextMenu( HWND h, QPoint & point );



    virtual bool OnMouseMove( UINT flags, QPoint & point );
    virtual bool OnMouseHover( UINT nFlags, QPoint & point );
    virtual bool OnMouseLeave();

    virtual bool OnActivateApp( bool active, UINT_PTR threadID );
    virtual bool OnActivate( HWND hwnd, UINT active, UINT minMax );
    virtual bool OnMouseActivate( HWND hwnd, UINT nHitTest, UINT message, LRESULT & lResult );

    virtual bool OnNcActivate( bool active, LRESULT & lr );


    virtual bool OnNcPaint( WPARAM wParam, LPARAM lParam  );
    virtual bool OnNcCalcSize( WPARAM indicate, NCCALCSIZE_PARAMS * lParam );
    virtual bool OnNcHitTest( QPoint & pt, LRESULT & lr );

    virtual bool OnNcMouseMove( UINT flags, QPoint & point );
    virtual bool OnNcMouseHover( UINT nFlags, QPoint & point );
    virtual bool OnNcMouseLeave();

    virtual bool OnNcLButtonDown( UINT flags, QPoint & point );
    virtual bool OnNcLButtonUp( UINT flags, QPoint & point );
    virtual bool OnNcLButtonDblClk( UINT flags, QPoint & point );
    virtual bool OnNcRButtonDown( UINT flags, QPoint & point );
    virtual bool OnNcRButtonUp( UINT flags, QPoint & point );
    virtual bool OnNcRButtonDblClk( UINT flags, QPoint & point );
    virtual bool OnNcMButtonDown( UINT flags, QPoint & point );
    virtual bool OnNcMButtonUp( UINT flags, QPoint & point );
    virtual bool OnNcMButtonDblClk( UINT flags, QPoint & point );





    virtual	bool OnCaptureChanged();
    virtual bool OnChar( UINT nChar, UINT nRepCnt, UINT nFlags );
    virtual bool OnSysChar( UINT nChar, UINT nRepCnt, UINT nFlags );
    virtual bool OnKeyUp( UINT nChar, UINT nRepCnt, UINT nFlags );
    virtual bool OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags );




    virtual bool OnHotKey( UINT nHotKeyId, UINT nKey1, 	UINT nKey2 );
    bool  RegisterHotKey( int id, UINT fsMod, UINT vk )
    {
        return 0 != ::RegisterHotKey( _window, id, fsMod, vk );
    }
    bool  UnregisterHotKey( int id )
    {
        return 0 != ::UnregisterHotKey( _window, id );
    }






    virtual bool OnVScroll( UINT code, UINT pos );
    virtual bool OnHScroll( UINT code, UINT pos );

    virtual bool OnGetDlgCode();
    virtual bool OnSysColorChange();

    virtual	bool OnSetFocus( HWND hwnd );
    virtual	bool OnKillFocus( HWND hwnd );
    virtual bool OnSetCursor( UINT nHitTest, UINT message );

    virtual bool OnDrawClipboard();
    virtual bool OnChangeCbChain( HWND, HWND );
    virtual bool OnDeviceChange( WPARAM nEventType, LPARAM dwData ); //disks
    virtual bool OnThemeChanged();
    virtual bool OnCtlColorEdit();


#if( WINVER>=_WIN32_WINNT_WIN7)
    bool RegisterTouchWindow( UINT flags = 0 )
    {
        return 0 != ::RegisterTouchWindow( _window,  flags );
    }

    bool UnregisterTouchWindow()
    {
        return toBool( ::UnregisterTouchWindow( _window ) );
    }


    virtual bool OnTouch( HTOUCHINPUT  ht, UINT nr );

    virtual bool OnGestureNotify();
    virtual bool OnGesture( HGESTUREINFO  lParam );
    virtual bool OnCompositionChanged();

#endif



public:
    virtual bool GetText( QString & s ) const;
    virtual bool SetText( LPCTSTR s )
    {
        return  0 != ::SetWindowText( _window, s );
    }
    virtual int	 GetTextLength() const
    {
        return  ::GetWindowTextLength( _window );
    }

    ///QWindow&	operator=(HWND newWindow) {  _window = newWindow;  return *this;  }

    /*
    		inline    operator HWND() const
    		{
    			return _window;
    		}
    */
    inline    HWND GetHandle( void )
    {
        return _window;
    }


    bool		Destroy();
    void		Attach( HWND newWindow )
    {
        _window = newWindow;
    }
    HWND		Detach()
    {
        HWND window = _window;
        _window = nullptr;
        return window;
    }
    void		SetFont( HFONT hFont, BOOL bRedraw = FALSE );
    HFONT		GetFont() const;





    HWND		GetParent()    const
    {
        return ::GetParent( _window );
    }

    QRect		GetWindowRect()const
    {
        QRect rc;
        ::GetWindowRect( _window, &rc );
        return rc;
    }
    QRect		GetClientRect()const
    {
        QRect rc;
        ::GetClientRect( _window, &rc );
        return rc;
    }
    void		GetWindowRect( QRect & rc )const
    {
        ::GetWindowRect( _window, &rc );
    }
    void		GetClientRect( QRect & rc )const
    {
        ::GetClientRect( _window, &rc );
    }



    bool		ClientToScreen( QPoint & point ) const
    {
        return toBool( ::ClientToScreen( _window, point ) );
    }
    bool		ScreenToClient( QPoint & point ) const
    {
        return toBool( ::ScreenToClient( _window, point ) );
    }

    void		ClientToScreen( QRect & rect )   const ;
    void		ScreenToClient( QRect & rect )   const ;

    bool		OpenClipboard()
    {
        return toBool( ::OpenClipboard( _window ) );
    }

    void		GetCursorPos( QPoint & point )  const
    {
        ::GetCursorPos( point );
    }
    QPoint 		GetCursorPos( ) const
    {
        QPoint pt;
        ::GetCursorPos( pt );
        return pt;
    }
    void		SetCursorPos( QPoint & point )  const
    {
        ::SetCursorPos( point.x, point.y );
    }

    int			GetDlgCtrlID()
    {
        return ::GetDlgCtrlID( _window );
    }
    HWND		GetDlgItem( UINT nID )
    {
        return ::GetDlgItem( _window, nID );
    }

    void SetCapture()
    {
        ::SetCapture( _window );
    }
    void ReleaseCapture()
    {
        ::ReleaseCapture();
    }



    bool		IsZoomed()	const
    {
        return toBool( ::IsZoomed( _window ) );
    }
    bool		IsWindow()  const
    {
        return toBool( ::IsWindow( _window ) );
    }
    bool		IsVisible() const
    {
        return toBool( ::IsWindowVisible( _window ) );
    }
    bool		IsIconic()  const
    {
        return toBool( ::IsIconic( _window ) );
    }

    bool		IsCtrlDown()	const
    {
        return toBool( ::GetKeyState( VK_CONTROL ) & 0x8000 );
    }
    bool		IsShiftDown()	const
    {
        return toBool( ::GetKeyState( VK_SHIFT ) & 0x8000 );
    }
    bool		IsAltDown()		const
    {
        return toBool( ::GetKeyState( VK_MENU ) & 0x8000 );
    }



    bool		MoveWindow( int x, int y, int width, int height, bool repaint = true )
    {
        return toBool( ::MoveWindow( _window, x, y, width, height, toBOOL( repaint ) ) );
    }


    bool		MoveWindow( QRect r, bool repaint = true )
    {
        return toBool( ::MoveWindow( _window, r.left, r.top, r.Width(), r.Height(), toBOOL( repaint ) ) );
    }

    bool		SetForegroundWindow()
    {
        return 0 != ::SetForegroundWindow( _window );
    }
    bool		Show( int show = SW_SHOW )
    {
        return 0 !=::ShowWindow( _window, show );
    }
    bool		Hide(  )
    {
        return ( bool ) 0 != ::ShowWindow( _window, SW_HIDE );
    }
    bool		ShowScrollBar( int bar, bool bShow )
    {
        return toBool( ::ShowScrollBar( _window, bar, bShow ) );
    }
    void		SetFocus()
    {
        ::SetFocus( _window );    //la unele cotroale si panele merge diferit
    }

    //void KillFocus() {  /*to be implemented in derived calses  */     }
    void		SetScrollInfo( int fnBar, LPCSCROLLINFO lpsi, bool fRedraw )
    {
        ::SetScrollInfo( _window, fnBar, lpsi, fRedraw );
    }
    void		GetScrollInfo( int fnBar, LPSCROLLINFO lpsi )
    {
        ::GetScrollInfo( _window, fnBar, lpsi );
    }

    int			ScrollWindow( int dx, int dy, const RECT * prcScroll, const RECT * prcClip, HRGN hrgnUpdate = nullptr, RECT * prcUpdate = nullptr, UINT flags = SW_INVALIDATE )
    {
        return  ::ScrollWindowEx( _window, dx, dy, prcScroll, prcClip, hrgnUpdate, prcUpdate,  flags );
    }


    void		ModifyStyle( DWORD dwRemove, DWORD dwAdd, DWORD dwFlags = 0 );
    void		ModifyExStyle( DWORD dwRemove, DWORD dwAdd, DWORD dwFlags = 0 );

    bool		SetPlacement( CONST WINDOWPLACEMENT * placement )
    {
        return toBool( ::SetWindowPlacement( _window, placement ) );
    }
    bool		GetPlacement( WINDOWPLACEMENT * placement )
    {
        return toBool( ::GetWindowPlacement( _window, placement ) );
    }

    bool		SetWindowPos( HWND hWndInsertAfter, int x, int y, int cx, int cy, UINT uFlags )
    {
        return toBool( ::SetWindowPos( _window, hWndInsertAfter, x,  y,  cx,  cy, uFlags ) );
    }
    bool		SetWindowPos( HWND hWndInsertAfter, QRect rc, UINT uFlags )
    {
        return  SetWindowPos( hWndInsertAfter, rc.left,  rc.top,  rc.Width(),  rc.Height(), uFlags );
    }

    bool SetWindowPlacement( const WINDOWPLACEMENT * wp )
    {
        return 0 !=::SetWindowPlacement( _window, wp );
    }

    bool GetWindowPlacement( WINDOWPLACEMENT * wp )
    {
        return 0 !=::GetWindowPlacement( _window, wp );
    }


    bool		InvalidateRect( LPCRECT rect, bool backgroundErase = true )
    {
        return   0 != ::InvalidateRect( _window, rect, ( BOOL )  backgroundErase  );
    }
    bool		Invalidate( bool bErase = true ) const
    {
        return 0 !=::InvalidateRect( _window, nullptr, ( BOOL )bErase );
    }
    bool		RedrawWindow( QRect * lpRectUpdate = nullptr, HRGN hRgnUpdate = nullptr, UINT flags = RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE ) throw()
    {
        return toBool( ::RedrawWindow( _window, lpRectUpdate, hRgnUpdate, flags ) );
    }

    bool		UpdateWindow()
    {
        return toBool( ::UpdateWindow( _window ) );
    }
    //bool UpdateWindow() { return (bool)::UpdateWindow(_window);

    void		SetRedraw( bool redraw = true )
    {
        SendMessage( WM_SETREDRAW, toBOOL( redraw ), 0 );
    }



    //need	#include <uxtheme.h> //SetWindowTheme
    void		SetWindowTheme( LPCWSTR str, LPCWSTR id = 0 )
    {
        ::SetWindowTheme( _window, str, id );
    }




    LONG_PTR	SetWindowLong( int index, LONG_PTR newLongPtr )
    {
        return ::SetWindowLongPtr( _window, index, newLongPtr );
    }
    LONG_PTR	GetWindowLong( int index ) const
    {
        return ::GetWindowLongPtr( _window, index );
    }
    LONG_PTR	SetClassLong( int index, LONG_PTR newLongPtr )
    {
        return ::SetClassLongPtr( _window, index, newLongPtr );
    }
    LONG_PTR	GetClassLong( int index ) const
    {
        return ::GetClassLongPtr( _window, index );
    }

    LONG_PTR	SetStyle( LONG_PTR style )
    {
        return SetWindowLong( GWL_STYLE, style );
    }
    LONG_PTR	GetStyle( ) const
    {
        return GetWindowLong( GWL_STYLE );
    }

    LONG_PTR	GetExStyle()const
    {
        return GetWindowLong( GWL_EXSTYLE );
    }
    LONG_PTR	SetExStyle( LONG_PTR style )
    {
        return SetWindowLong( GWL_EXSTYLE, style );
    }

    LONG_PTR	SetUserDataLong( LONG_PTR newLongPtr )
    {
        return SetWindowLong( GWLP_USERDATA, newLongPtr );
    }
    LONG_PTR	GetUserDataLong() const
    {
        return GetWindowLong( GWLP_USERDATA );
    }

    bool EnableWindow( bool enable )
    {
        return toBool( ::EnableWindow( _window, toBOOL( enable ) ) );
    }
    bool IsEnabled()
    {
        return toBool( ::IsWindowEnabled( _window ) );
    }
    HMENU GetMenu( )
    {
        return ::GetMenu( _window );
    }
    HMENU GetSystemMenu( bool revert )
    {
        return ::GetSystemMenu( _window, toBOOL( revert ) );
    }
	void SetMenu(HMENU menu)
	{
		::SetMenu(_window, menu);
	}

    UINT_PTR SetTimer( UINT_PTR idEvent, UINT elapse, TIMERPROC timerFunc = 0 )
    {
        return ::SetTimer( _window, idEvent, elapse, timerFunc );
    }
    bool KillTimer( UINT_PTR idEvent )
    {
        return toBool( ::KillTimer( _window, idEvent ) );
    }

    int	GetScrollPos( int nBar )
    {
        return ::GetScrollPos( _window, nBar );
    }


};


class QTrackMouseEvent //: public TRACKMOUSEEVENT
{
protected:
    bool m_bMouseTracking;
    TRACKMOUSEEVENT track;


public:
    QTrackMouseEvent()
    {
        m_bMouseTracking = false;
    }
    bool IsTracking()
    {
        return m_bMouseTracking;
    }
    void StopTrackEvents()
    {
        m_bMouseTracking = false;
    }


    bool TrackMouseEvents( QWindow * pwin, DWORD dwFlags = TME_LEAVE | TME_HOVER, //  | TME_NONCLIENT ,
                           DWORD dwHoverTime = 10 )
    {
        ASSERT( pwin );
        ASSERT( ::IsWindow( pwin->GetHandle() ) );

        track.cbSize = sizeof( TRACKMOUSEEVENT );
        track.dwFlags = dwFlags;
        track.hwndTrack = pwin->GetHandle();
        track.dwHoverTime = dwHoverTime;

        m_bMouseTracking = TrackMouseEvent( &track ) == TRUE;

        return m_bMouseTracking;
    }
};



//
// template <DWORD t_dwStyle = 0, DWORD t_dwExStyle = 0>
// class CWinTraits
// {
// public:
// 	static DWORD GetWndStyle( _In_ DWORD dwStyle )
// 	{
// 		return dwStyle == 0 ? t_dwStyle : dwStyle;
// 	}
// 	static DWORD GetWndExStyle( _In_ DWORD dwExStyle )
// 	{
// 		return dwExStyle == 0 ? t_dwExStyle : dwExStyle;
// 	}
// };
//
// typedef CWinTraits < WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0 >					CControlWinTraits;
// typedef CWinTraits < WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE >		CFrameWinTraits;
// typedef CWinTraits < WS_OVERLAPPEDWINDOW | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_MDICHILD >	CMDIChildWinTraits;
//




}//gui
}//micro




